/*
 * Copyright (c) zhg2yqq.com Corp.
 * All Rights Reserved.
 */
package com.zhg2yqq.wheels.security.multi;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * 账号密码登陆
 *
 * @author zhg2yqq, 2023年3月16日
 * @version zhg2yqq v1.0
 */
public class NormalAuthenticationTokenHandler {
    public static final String TYPE = "NORMAL";

    public static class NormalAuthenticationTokenFactory implements IAuthenticationTokenFactory {

        @Override
        public String type() {
            return TYPE;
        }

        @Override
        public CustomAuthenticationToken create(AuthenticationTokenParameter parameter) {
            return new NormalAuthenticationToken(parameter);
        }
    }

    public static class NormalAuthenticationToken extends CustomAuthenticationToken {
        private static final long serialVersionUID = 1L;
        protected final Log logger = LogFactory.getLog(getClass());
        protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

        public NormalAuthenticationToken(AuthenticationTokenParameter parameter) {
            super(TYPE, parameter.getUsername(), parameter.getPassword());
        }

        @Override
        public UserDetails retrieveUser(UserDetailsService userDetailsService)
                throws AuthenticationException {
            UserDetails loadedUser = userDetailsService.loadUserByUsername(getName());
            if (loadedUser == null) {
                throw new InternalAuthenticationServiceException(
                        "UserDetailsService returned null, which is an interface contract violation");
            }
            return loadedUser;
        }

        @Override
        protected void postAuthenticationCheck(UserDetails userDetails,
                                               TokenCheckHelper checkHelper)
                throws AuthenticationException {
            if (getCredentials() == null) {
                this.logger.debug("Failed to authenticate since no credentials provided");
                throw new BadCredentialsException(this.messages.getMessage(
                        "AbstractUserDetailsAuthenticationProvider.badCredentials",
                        "Bad credentials"));
            }
            String presentedPassword = getCredentials().toString();
            if (!checkHelper.getPasswordEncoder().matches(presentedPassword,
                    userDetails.getPassword())) {
                this.logger
                        .debug("Failed to authenticate since password does not match stored value");
                throw new BadCredentialsException(this.messages.getMessage(
                        "AbstractUserDetailsAuthenticationProvider.badCredentials",
                        "Bad credentials"));
            }
            super.postAuthenticationCheck(userDetails, checkHelper);
        }
    }
}
